package ar.edu.sovietrussia.customcomponents.bookviews;

import java.util.List;
import java.util.Map;

import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import services.book.BookService;
import services.book.ReservationService;
import users.Person;
import ar.edu.sovietrussia.customcomponents.loaning.LoanConfirmationComponent;
import ar.edu.sovietrussia.customcomponents.util.IDoReplaces;
import ar.edu.sovietrussia.customcomponents.util.IFeedbacker;
import ar.edu.sovietrussia.customcomponents.util.WrapperPanel;
import books.BookInfo;
import books.BookReservation;
import dtos.BookInfoDTO;

/**
 */
public abstract class DetailedBookViewPanel extends Panel implements IFeedbacker, IDoReplaces {

    private static final long serialVersionUID = 1L;

    private boolean available = false;

    private boolean reserved = false;

    private boolean personHasReservation = false;

    private boolean logged = false;

    private Person person;

    @SpringBean
    private BookService bookService;

    @SpringBean
    private ReservationService reservationService;

    public DetailedBookViewPanel(final String id, final BookModel model) {
        super(id, model);
        this.logged = (Person) this.getSession().getAttribute("model") != null;
        if (this.logged) {
            this.person = (Person) this.getSession().getAttribute("model");
            this.available = this.getBookService().copyAvailableDTO(model.getObject());
            this.reserved = this.getReservationService().isReservedDTO(model.getObject());
            this.personHasReservation = this.getReservationService().personHasReserved(this.person, model.getObject());
        }

        this.addComponents();

    }

    private void addComponents() {

        BookInfoDTO modelObject = (BookInfoDTO) this.getDefaultModelObject();

        this.add(new Label("title"));
        this.add(new Label("description"));
        this.add(new Label("isbn"));
        this.add(new Label("authors"));
        this.add(new Label("publisher", new PropertyModel(modelObject.getPublisher(), "name")));
        this.add(new Label("categories"));
        this.add(new Label("registrationDate"));

        this.add(new Label("title_label", "Title:"));
        this.add(new Label("isbn_label", "ISBN:"));
        this.add(new Label("publisher_label", "Publiser:"));
        this.add(new Label("description_label", "Description:"));
        this.add(new Label("authors_label", "Authors:"));
        this.add(new Label("categories_label", "Categories:"));
        this.add(new Label("date_label", "Registration date:"));

        this.addLoanLink("loanLink");
        this.addReserveLink("reserveLink");
        this.addNotificationListLink("notificationLink");
        this.addCancelReservationLink("cancelReservationLink");

        this.add(new Label("relatedBooksLabel", "Otras personas tambien alquilaron:"));
        this.addRelatedBooksPanel("relatedBooks");
    }

    private void addRelatedBooksPanel(final String id) {
        BookInfoDTO book = (BookInfoDTO) this.getDefaultModelObject();
        List<BookInfoDTO> books = this.getBookService().loanRelatedBooksDTO(book);

        BooksDataTable panel = new BooksDataTable(id, books) {
            private static final long serialVersionUID = 1L;

            @Override
            public void onDetailsLinkClicked(final BookInfoDTO book) {
                DetailedBookViewPanel.this.onSelectedBook(new BookModel(book));
            }
        };

        this.add(panel);
    }

    protected void onSelectedBook(final BookModel bookModel) {
        this.doResponse(bookModel);
    }

    private void addCancelReservationLink(final String id) {
        Link link = new Link<String>(id) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {

                DetailedBookViewPanel.this.onCancelReservationLinkClicked((BookInfoDTO) DetailedBookViewPanel.this
                        .getDefaultModelObject());
            }

        };
        link.setVisible(this.isLogged() & this.isPersonHasReservation());
        this.add(link);
    }

    protected void onCancelReservationLinkClicked(final BookInfoDTO dto) {
        this.getReservationService().cancelReservationBookDTO(dto);

        this.getFeedbackTarget().info("Reserva cancelada");

        this.doResponse((BookModel) this.getDefaultModel());
    }

    private void addNotificationListLink(final String id) {
        Link link = new Link(id, new Model<String>("Agregarse a notificaciones")) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {

                DetailedBookViewPanel.this.onNotificationLinkClicked((BookInfoDTO) DetailedBookViewPanel.this
                        .getDefaultModelObject());
            }

        };
        link.setVisible(this.isLogged() & this.isReserved() & !this.isAvailable());
        this.add(link);
    }

    protected void onNotificationLinkClicked(final BookInfoDTO dto) {
        Person personmodel = (Person) this.getSession().getAttribute("model");
        BookInfo info = this.getBookService().findById(dto.getId());
        this.getReservationService().addToNotificationList(personmodel, info);

        this.getFeedbackTarget().info("Agregado a lista de notificaciones");

        this.doResponse((BookModel) this.getDefaultModel());
    }

    private void addReserveLink(final String id) {
        Link link = new Link(id, new Model<String>("Reservar")) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {

                DetailedBookViewPanel.this.onReserveLinkClicked((BookInfoDTO) DetailedBookViewPanel.this
                        .getDefaultModelObject());
            }

        };
        link.setVisible(this.isLogged() & !this.isReserved() & !this.isAvailable());
        this.add(link);

    }

    protected void onReserveLinkClicked(final BookInfoDTO bookDto) {
        BookInfo info = this.getBookService().findById(bookDto.getId());
        Person personmodel = (Person) this.getSession().getAttribute("model");
        BookReservation reservation = new BookReservation(info, personmodel);
        this.getReservationService().reserveTo(reservation);

        this.getFeedbackTarget().info("Libro reservado");
        this.doResponse((BookModel) this.getDefaultModel());
    }

    private void addLoanLink(final String id) {
        Link link = new Link(id, new Model<String>("Alquilar")) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {

                DetailedBookViewPanel.this.onLoanLinkClicked((BookInfoDTO) DetailedBookViewPanel.this
                        .getDefaultModelObject());
            }

        };
        link.setVisible(this.isLogged() & this.isAvailable());
        this.add(link);

    }

    public void onLoanLinkClicked(final BookInfoDTO bookDto) {
        Panel panel = new LoanConfirmationComponent(WrapperPanel.INTERNALID, bookDto) {
            private static final long serialVersionUID = -1483332141197329848L;

            @Override
            public FeedbackPanel getFeedbackTarget() {
                return DetailedBookViewPanel.this.getFeedbackTarget();
            }

            @Override
            public Map<String, WrapperPanel> getReplaceableComponents() {
                return DetailedBookViewPanel.this.getReplaceableComponents();
            }
        };
        this.getReplaceableComponents().get("topPanel").replace(panel);
    }

    public void doResponse(final BookModel model) {
        Panel refreshed = new DetailedBookViewPanel(this.getId(), model) {

            private static final long serialVersionUID = 1L;

            @Override
            public FeedbackPanel getFeedbackTarget() {
                return DetailedBookViewPanel.this.getFeedbackTarget();
            }

            @Override
            public Map<String, WrapperPanel> getReplaceableComponents() {
                return DetailedBookViewPanel.this.getReplaceableComponents();
            }

        };
        this.getReplaceableComponents().get("centerPanel").replace(refreshed);
    }

    public void setAvailable(final boolean available) {
        this.available = available;
    }

    public boolean isAvailable() {
        return this.available;
    }

    public void setReserved(final boolean reserved) {
        this.reserved = reserved;
    }

    public boolean isReserved() {
        return this.reserved;
    }

    public BookService getBookService() {
        return this.bookService;
    }

    public void setBookService(final BookService bookService) {
        this.bookService = bookService;
    }

    public ReservationService getReservationService() {
        return this.reservationService;
    }

    public void setReservationService(final ReservationService reservationService) {
        this.reservationService = reservationService;
    }

    public void setPersonHasReservation(final boolean personHasReservation) {
        this.personHasReservation = personHasReservation;
    }

    public boolean isPersonHasReservation() {
        return this.personHasReservation;
    }

    public Person getPerson() {
        return this.person;
    }

    public void setPerson(final Person person) {
        this.person = person;
    }

    public void setLogged(final boolean logged) {
        this.logged = logged;
    }

    public boolean isLogged() {
        return this.logged;
    }

}
